import { CallExpressionNode, ChildNode, NodeTypes, RootNode } from "./parser";

type ParentNode = RootNode | CallExpressionNode | undefined;
type MethodFn = (node: RootNode | ChildNode, parent: ParentNode) => void;

interface VisitorOption {
  enter: MethodFn;
  exit?: MethodFn;
}

export interface Visitor {
  Program?: VisitorOption;
  CallExpression?: VisitorOption;
  NumberLiteral?: VisitorOption;
  StringLiteral?: VisitorOption;
}

export function traverser(rootNode: RootNode, visitor: Visitor) {
  // 遍历树 深度优先搜索
  const traverArray = (array: ChildNode[], parent: ParentNode) => {
    array.forEach((node) => {
      traverNode(node, parent);
    });
  };

  const traverNode = (node: RootNode | ChildNode, parent?: ParentNode) => {
    const methods = visitor[node.type];

    // enter
    methods?.enter(node, parent);

    switch (node.type) {
      case NodeTypes.Program:
        traverArray((node as RootNode).body, node as RootNode);
        break;
      case NodeTypes.CallExpression:
        traverArray(
          (node as CallExpressionNode).params,
          node as CallExpressionNode
        );
        break;
      case NodeTypes.NumberLiteral:
        break;
      default:
        break;
    }

    // exit
    // if (methods && methods.exit) {
    //   methods.exit(node, parent);
    // }
    methods?.exit && methods.exit(node, parent);
  };

  traverNode(rootNode);
}
